﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Threading;
using Unity;
using Prism.Events;
using VNext.Core.Packs;
using VNext.Log4Net;

namespace CutPhotos
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : Application
    {
        private static Mutex mutex = new Mutex(true, "{3b3c4b1b-0e88-42ab-9f8d-1cc1b3d40d3e}"); // UUID generated specifically for this app
        private static Logger Logger;

        public App()
        {
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(HandleException);
            Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
            TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
            Application.Current.Exit += application_Exit;
            System.Diagnostics.Debugger.Log(1, "", $"{DateTime.Now.ToString("HH:mm:ss.ffffff")}: Started Application");
        }

        public static void Invoke(Action callback)
        {
            try
            {
                App.Current?.Dispatcher?.Invoke(callback);
            }
            catch (Exception ex)
            {
                Logger.LogException("Unable to invoke action on UI thread", ex);
            }
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            string assemblyName = assembly.GetName().Name;
            System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
            string version = fvi.FileVersion;
            WindowsIdentity user = WindowsIdentity.GetCurrent();

            MainWindow mainWindow = null;

            try
            {
                var container = new UnityContainer() { };
                RegisterTypes(container);
                Logger = container.Resolve<Logger>();
                mainWindow = container.Resolve<MainWindow>();
            }
            catch (Exception ex)
            {
                Logger.LogException("Failed to boot print manager and the main window", ex);
                Environment.Exit(1);
            }

            var startupMessage = $"{assemblyName} version {version} started at {DateTime.Now} by user {user.Name}.";
            startupMessage = $"Attempting to start {assemblyName} version {version} at {DateTime.Now} by user {user.Name}.";
            Logger.LogInformation("==================================================================================");
            Logger.LogInformation(startupMessage);
            Logger.LogInformation($"Current Directory = {Environment.CurrentDirectory}");
            Logger.LogInformation("==================================================================================");

            try
            {
                FontFamily font;
                font = new FontFamily("Noto Sans SC");

                FrameworkElement.LanguageProperty.OverrideMetadata(
                    typeof(FrameworkElement),
                    new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

                TextElement.FontFamilyProperty.OverrideMetadata(
                    typeof(TextElement),
                    new FrameworkPropertyMetadata(font));

                TextBlock.FontFamilyProperty.OverrideMetadata(
                    typeof(TextBlock),
                    new FrameworkPropertyMetadata(font));

                Control.FontFamilyProperty.OverrideMetadata(
                    typeof(Button),
                    new FrameworkPropertyMetadata(font));
            }
            catch (Exception ex)
            {
                Logger.LogException("Failed to load user preferences and set language", ex);
                Environment.Exit(1);
            }

            //#if DEBUG
            // Visual Studio killing the app sometimes leaves a zombie mutex, so we only put it in the release version.
            //#else

            if (mutex.WaitOne(TimeSpan.Zero, true))
            {
                mutex.ReleaseMutex();
            }
            else
            {
                MessageBox.Show("Please only run one instance of PrintController at a time.", "PrintController is already running", MessageBoxButton.OK);
                Environment.Exit(1);
            }
            //#endif

            mainWindow.Show();
        }

        public static void HandleException(object sender, UnhandledExceptionEventArgs args)
        {
            try
            {
                if (args.ExceptionObject is Exception e)
                {
                    Logger.LogException($"Unhandled exception of type {e.GetType().Name} in the application. Application is {(args.IsTerminating ? "" : "not ")}terminating", e);
                }
                else
                {
                    Logger.LogError($"Unhandled exception in the application, error: {args.ExceptionObject?.ToString()}. Application is {(args.IsTerminating ? "" : "not ")}terminating");
                }
            }
            catch
            {
                // OK, not even logging works any more...
            }
        }

        private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = true;
            try
            {
                Logger.LogException($"Unhandled dispatcher exception of type {e.GetType().Name} in the application.", e.Exception);
            }
            catch
            {
                // OK, not even logging works any more...
            }
        }

        private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
        {
            try
            {
                Logger.LogException($"Unhandled task exception of type {e.GetType().Name} in the application.", e.Exception);
            }
            catch
            {
                // OK, not even logging works any more...
            }
        }

        private void application_Exit(object sender, ExitEventArgs e)
        {
            try
            {

            }
            catch (Exception ex)
            {

            }

            Logger.LogInformation($"Application exiting");
        }

        private void RegisterTypes(IUnityContainer container)
        {
            //container.RegisterInstance<IUIHelpers>(null);
            PackBuilder.AddServices(container);
        }
    }
}
